package com.dy.yunying.biz.service.yyz.impl;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dy.yunying.api.base.BaseDto;
import com.dy.yunying.api.constant.Constant;
import com.dy.yunying.api.entity.GameAppointment;
import com.dy.yunying.api.entity.SendMassage;
import com.dy.yunying.api.enums.RedisNameEnum;
import com.dy.yunying.api.req.yyz.GameAppointmentImportSendReq;
import com.dy.yunying.api.req.yyz.MsgReq;
import com.dy.yunying.api.req.yyz.SendMassageReq;
import com.dy.yunying.biz.config.YunYingProperties;
import com.dy.yunying.biz.dao.manage.SendMassageMapper;
import com.dy.yunying.biz.service.yyz.SendMassageService;
import com.dy.yunying.biz.utils.ReadExcelTools;
import com.dy.yunying.biz.utils.SendMessageBST;
import com.google.common.collect.Lists;
import com.pig4cloud.pig.common.core.util.R;
import com.sjda.framework.sms.pojo.SmsEntity;
import com.sjda.framework.sms.pojo.SmsEnum;
import com.sjda.framework.sms.service.SmsSender;
import com.sjda.framework.sms.service.TencentSmsSender;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Author: kyf
 * @Date: 2020/12/9 16:47
 */
@Slf4j
@Service
//@RefreshScope
@RequiredArgsConstructor
public class SendMassageServiceImpl extends ServiceImpl<SendMassageMapper, SendMassage> implements SendMassageService {

	private final SendMassageMapper sendMassageMapper;

	@Autowired
	private SmsSender smsSender;
	@Autowired
	private TencentSmsSender tencentSmsSender;
	@Autowired
	private RedisTemplate<String, String> redisTemplate;
	@Autowired
	private YunYingProperties yunYingProperties;

	@SentinelResource(value = "/sendMessage/sendSms")
	@Override
	public R sendSms(MsgReq req) {
		//1. 解析请求参数
		log.info("获取手机验证码请求参数串 : " + BaseDto.toString(req));
		try {
			String mobile = req.getMobile();
			Integer type = req.getType();
			Integer codeType = req.getCodeType();//预约来源（1：PC  2：H5）
			String captcha = req.getCaptcha();
			String random = req.getRandom();
			//图形验证码
			String yzm = redisTemplate.opsForValue().get(RedisNameEnum.SCAPTCHA_KEY.get(codeType) + "_" + random);
			if (StringUtils.isBlank(yzm)) {
				log.info("图形验证码错误或已失效");
				return R.failed("图形验证码错误或已失效");
			}
			if (!captcha.equals(yzm)) {
				log.info("图形验证码输入错误");
				return R.failed("图形验证码输入错误");
			}
			//删除图形验证码
			redisTemplate.delete(RedisNameEnum.SCAPTCHA_KEY.get(codeType) + "_" + random);
			//发送短信
			return this.sendMsg(mobile,type, codeType, random);
		} catch (Exception e) {
			log.error("短信发送失败: ", e);
			return R.failed("获取验证码失败");
		}
	}

	private R sendMsg(String mobile,Integer type ,Integer codeType, String random) {
		String timeKey = redisTemplate.opsForValue().get(RedisNameEnum.SMS_CODE_TIME.get(mobile) + "_" + codeType + "_" + random);
		if (StringUtils.isNotBlank(timeKey)) {
			Long time = Long.parseLong(timeKey);
			// 存在验证码且再次获取时间在1分钟之内（此处为55秒，因为存在前后台时间交互差）
			if (time != null) {
				long now = new Date().getTime();
				if (now - time < 55 * 1000) {//"验证码已发送至手机!"
					return R.failed("验证码已经发送至手机，1分钟之内请勿重复发送");
				}
			}
		}
		//发送短信存储记录日志
		SendMassage sendMassage=new SendMassage();
		sendMassage.setMobile(mobile);
		sendMassage.setType(type.toString());
		sendMassage.setSendTime(new Date());
		//移除之前的验证码缓存
		redisTemplate.delete(RedisNameEnum.SMS_CODE.get(mobile) + "_" + codeType + "_" + random);
		redisTemplate.delete(RedisNameEnum.SMS_CODE_TIME.get(mobile) + "_" + codeType + "_" + random);
		//腾讯
		SmsEntity sms = new SmsEntity();
		sms.setMobile(mobile);
		sms.setMsgType(SmsEnum.MSG_TYPE_CODE.getValue());
		sms.setCodeSize(6);
		sms.setSecretId(yunYingProperties.getSecretId());//secretid
		sms.setSecretKey(yunYingProperties.getSecretKey());//App Key
		sms.setSignName(yunYingProperties.getSignName());//签名
		sms.setSmsSdkAppid(yunYingProperties.getSmsSdkAppid());//SDK AppID
		sms.setTemplateCode(yunYingProperties.getTemplateCode());//短信模板   875447  877185
		//sms.setTemplateParams();
		//测试调用短信验证
		Map<String, Object> result;
		//result = smsSender.pretendSendSms(sms);
		//线上腾讯
		result = tencentSmsSender.sendSms(sms);

		log.info("调用手机验证码接口返回，result:[{}]", result.toString());
		if (CollectionUtils.isEmpty(result) || !result.containsKey("status")
				|| !StringUtils.equals(Constant.RESULT_STATUS_SUCCESS, result.get("status").toString())) {
			log.error("获取手机验证码失败，error:{}", "接口调用失败");
			sendMassage.setIsSuccess(2);
			sendMassageMapper.insert(sendMassage);
			return R.failed("获取验证码失败");
		}
		redisTemplate.opsForValue().set(RedisNameEnum.SMS_CODE.get(mobile) + "_" + codeType + "_" + random, result.get("data").toString(), 300, TimeUnit.SECONDS);
		redisTemplate.opsForValue().set(RedisNameEnum.SMS_CODE_TIME.get(mobile) + "_" + codeType + "_" + random, String.valueOf(new Date().getTime()), 60, TimeUnit.SECONDS);
		sendMassage.setIsSuccess(1);
		log.info("短信验证码发送成功,smsCode:[{}] ", result.get("data").toString());
		sendMassageMapper.insert(sendMassage);
		return R.ok(result.get("data"), "短信验证码已发送");
	}

	/***
	 * 批量发送短信-腾讯
	 * @param list
	 * @param sendType
	 * @return
	 */
	public R batchSendMsg(List<GameAppointment> list, Integer sendType) {
		List<Set> numbers = null;
		Map<String, Object> result;
		SmsEntity sms = new SmsEntity();
		//sms.setMobile(mobile);
		sms.setMsgType(SmsEnum.MSG_TYPE_CODE.getValue());
		sms.setCodeSize(6);

		sms.setSecretId(yunYingProperties.getSecretId());//secretid
		sms.setSecretKey(yunYingProperties.getSecretKey());//App Key
		sms.setSignName(yunYingProperties.getSignName());//签名
		sms.setSmsSdkAppid(yunYingProperties.getSmsSdkAppid());//SDK AppID
		sms.setTemplateCode(yunYingProperties.getTemplateCode());//短信模板   875447  877185

		//secretid
/*		sms.setSecretId(yunYingProperties.getSecretId());
		//App Key
		sms.setSecretKey(yunYingProperties.getSecretKey());
		//签名
		sms.setSignName(yunYingProperties.getSignName());
		//SDK AppID
		sms.setSmsSdkAppid(yunYingProperties.getSmsSdkAppid());
		//短信模板
		sms.setTemplateCode("820118");*/

		//发送短信存储记录日志
		SendMassage sendMassage=new SendMassage();
		StringBuffer mobileBuffer = new StringBuffer();
		int type = 1;
		//组装物品列
		for(GameAppointment appointment : list) {
			if (list.size() - 1 != list.indexOf(appointment)) {
				mobileBuffer.append(appointment.getMobile()).append(",");
			} else if (list.size() - 1 == list.indexOf(appointment)) {
				mobileBuffer.append(appointment.getMobile());
			}
			type = appointment.getType();
		}
		sendMassage.setMobile(mobileBuffer.toString());
		sendMassage.setType(String.valueOf(type));
		sendMassage.setSendTime(new Date());
		if (sendType == 2) {
			//2.有参数模板动态参数
			for (GameAppointment appointment : list) {
				String[] phoneNumbers = new String[]{"+86" + appointment.getMobile()};
				sms.setPhoneNumbers(phoneNumbers);
				String[] templateParams = new String[]{appointment.getMobile()};
				sms.setTemplateParams(templateParams);
				log.info("批量发送短信,req:{}" + BaseDto.toString(sms));
				result = tencentSmsSender.sendSmsBatch(sms);
				log.info("调用批量发送短信接口返回，result:[{}]", result.toString());
				if (CollectionUtils.isEmpty(result) || !result.containsKey("status")
						|| !StringUtils.equals(Constant.RESULT_STATUS_SUCCESS, result.get("status").toString())) {
					log.error("批量发送短信失败，error:{}", "接口调用失败");
					sendMassage.setMobile(Arrays.toString(phoneNumbers));
					sendMassage.setIsSuccess(2);
					sendMassageMapper.insert(sendMassage);
					return R.failed("批量发送短信");
				}
			}
		} else {
			if (sendType == 1) {
				//1.有参数模板固定参数
				String[] templateParams = new String[]{"固定参数"};
				sms.setTemplateParams(templateParams);
			}
			numbers = getPhoneNumberSets(list);
			for (Set<String> set : numbers) {
				String[] mobile = set.toArray(new String[set.size()]);
				sms.setPhoneNumbers(mobile);
				log.info("批量发送短信,req:{}" + BaseDto.toString(sms));
				result = tencentSmsSender.sendSmsBatch(sms);
				log.info("调用批量发送短信接口返回，result:[{}]", result.toString());
				if (CollectionUtils.isEmpty(result) || !result.containsKey("status") || !StringUtils.equals(Constant.RESULT_STATUS_SUCCESS, result.get("status").toString())) {
					log.error("批量发送短信失败，error:{}", "接口调用失败");
					sendMassage.setMobile(Arrays.toString(mobile));
					sendMassage.setIsSuccess(2);
					sendMassageMapper.insert(sendMassage);
					return R.failed("批量发送短信失败");
				}
			}
		}
		sendMassage.setIsSuccess(1);
		sendMassageMapper.insert(sendMassage);
		return R.ok(null, "批量发送短信成功");
	}

	/***
	 * 批量发送短信博士通
	 * @param req
	 * @return
	 */
	@Override
	public R batchSendMsg(SendMassageReq req) {
		List<String> mobileList;
		List<String> phoneNumberString=new ArrayList<>();
		SendMassage sendMassage=new SendMassage();
		if(org.apache.commons.lang3.StringUtils.isNotBlank(req.getMobiles())){
			mobileList= Arrays.asList(req.getMobiles().split(","));
		}else {
			mobileList = sendMassageMapper.selectGameAppointmentList(req);
		}

		if(mobileList.size() >=1){
			phoneNumberString = getPhoneNumberString(mobileList);
		}else {
			log.info("收件人不能为空");
			return R.failed(6, "收件人不能为空");
		}
		String message = sendMassageMapper.selectMessage(req);
		for(String mobile :phoneNumberString){
			Boolean flag = SendMessageBST.sendMesBst(mobile, message);
			//Boolean flag = true;
			sendMassage.setMobile(mobile);
			if (StringUtils.isBlank(req.getType())){
				sendMassage.setType("0");
			}else {
				sendMassage.setType(req.getType());
			}
			sendMassage.setSendTime(new Date());
			sendMassage.setIsSuccess(1);
			if (!flag) {
				sendMassage.setIsSuccess(2);
				return R.failed(6,"批量发送短信失败");
			}
			sendMassageMapper.insert(sendMassage);
		}
		return R.ok(1, "批量发送短信成功");
	}


	@Override
	public R bathImportSend(GameAppointmentImportSendReq req) {
		try {
			int failCount = 0;
			List<String> mobileList;
			int i = 0;
			StringBuilder builder = new StringBuilder();
			SendMassage sendMassage=new SendMassage();
			List<String[]> strList = ReadExcelTools.readExcel(req.getFile(), 0);
			if (!com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(strList)) {
				for (String[] str : strList) {
					if (str[0].length() <= 0 ) {
						continue;
					} else if (str[0].length() <= 0 || str[0].length() > 5000) {
						failCount += 1;
						continue;
					}
					if(i % 1000 == 999){
						builder.append(str[0]);
						builder.append("-");
						i=-1;
					}else {
						builder.append(str[0]);
						builder.append(",");
					}
					i++;
				}
				String[] mobiles = builder.substring(0,builder.length()-1).split("-");
				mobileList=Arrays.asList(mobiles);
				if(mobileList.size() < 1) {
					return R.failed(6, "收件人不能为空");
				}
				//发送短信
				SendMassageReq sendMassageReq =new SendMassageReq();
				sendMassageReq.setCode(req.getCode());
				String message = sendMassageMapper.selectMessage(sendMassageReq);
				for(String mobile :mobileList){
					Boolean flag = SendMessageBST.sendMesBst(mobile, message);
					//Boolean flag = true;
					sendMassage.setMobile(mobile);
					sendMassage.setType("0");//表示导入电话发送短信
					sendMassage.setSendTime(new Date());
					sendMassage.setIsSuccess(1);
					if (!flag) {
						sendMassage.setIsSuccess(2);
						return R.failed(6,"批量发送短信失败");
					}
					sendMassageMapper.insert(sendMassage);
				}
				if (failCount > 0) {
					return R.failed("数据导入完成，其中【" + failCount + "】条数据失败！");
				}
			} else {
				return R.failed("数据导入失败，文件为空！");
			}
		} catch (Exception e) {
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			return R.failed("数据导入失败，" + e.getLocalizedMessage());
		}
		return R.ok(1, "批量发送短信成功！");
	}




	/***
	 * 组装批量短信手机号
	 * @param list
	 * @return
	 */
	private List<Set> getPhoneNumberSets(List<GameAppointment> list) {
		Set<String> phone = null;
		List<Set> numbers = Lists.newArrayList();
		if (list.size() <= 200) {
			phone = new HashSet<>();
			for (int i = 0; i < list.size(); i++) {
				GameAppointment appointment = list.get(i);
				phone.add("+86" + appointment.getMobile());
			}
			numbers.add(phone);
		} else {
			for (int i = 0; i < list.size(); i++) {
				GameAppointment appointment = list.get(i);
				if (i % 200 == 0) {
					phone = new HashSet<>();
					phone.add("+86" + appointment.getMobile());
					numbers.add(phone);
				} else if (i % 200 > 0) {
					phone.add("+86" + appointment.getMobile());
				}
			}
		}
		return numbers;
	}

	/***
	 * 组装批量短信手机号--博士通
	 * @param list
	 * @return
	 */
	private List<String> getPhoneNumberString(List<String> list) {
		List<String> mobileList;
		int i = 0;
		StringBuilder builder = new StringBuilder();
		for(String mobile :list){
			if(i % 1000 == 999){
				builder.append(mobile);
				builder.append("-");
				i=-1;
			}else {
				builder.append(mobile);
				builder.append(",");
			}
			i++;
		}
		String[] mobiles = builder.substring(0,builder.length()-1).split("-");
		mobileList=Arrays.asList(mobiles);
		return mobileList;
	}


}
